/******************************************************************************/
/*                                                                            */
/*  File: main.cpp                                                            */
/*  Author: bkenwright@xbdev.net                                              */
/*  URL: www.xbdev.net                                                        */
/*                                                                            */
/******************************************************************************/
/*
	.x directx parser/drawer tutorial/demo
*/
/******************************************************************************/



// Enable memory leak checking, you never know, little leaks sometimes sneak
// through, and this will let us know if one has
#include "stdafx.h"
#include <stdlib.h>
#include <crtdbg.h>


#include <windows.h>
#include <shellapi.h>
#include <stdio.h>

#pragma comment(lib, "D3d9.lib")
#pragma comment(lib, "D3dx9.lib")
#include <d3dx9.h>

using namespace std;

#include "common.h"
#include "xtxtloader.h"
#include "xrender.h"
#include "Camera.h"

#include "Game.h"
#include "DirectInput.h"
#include <vld.h>

#define ID_FILE_OPEN 9001
int g_ScreenWidth = 1000;
int g_ScreenHeight = 700;

LPDIRECT3D9			g_pD3D				= NULL;
LPDIRECT3DDEVICE9	g_pD3DDevice		= NULL;
LPD3DXSPRITE		g_pD3DSprite		= NULL;
HWND				g_hWnd				= NULL;
float				g_timeStep			= 0.0f;
static float		g_zoom				= 1.0f;
bool				g_wire				= false;
bool				g_paused			= false;
bool				g_staticPose		= false;
bool				g_drawNormals		= false;
bool				g_drawBones			= false;
bool				g_transparent		= false;

//------------------------------------------------------------------------------

bool CreateDX()
{
	g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	D3DDISPLAYMODE d3ddm;
	g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);


	D3DPRESENT_PARAMETERS d3dpp; 
	ZeroMemory(&d3dpp, sizeof(d3dpp));

	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = d3ddm.Format;
	d3dpp.BackBufferCount=1;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	d3dpp.EnableAutoDepthStencil = TRUE;

	HRESULT hr =
		g_pD3D->CreateDevice(	D3DADAPTER_DEFAULT, 
								D3DDEVTYPE_HAL,
								g_hWnd, 
								D3DCREATE_MIXED_VERTEXPROCESSING,
								&d3dpp, 
								&g_pD3DDevice);
	if (hr!=S_OK)
	{
		hr =
		g_pD3D->CreateDevice(	D3DADAPTER_DEFAULT, 
								D3DDEVTYPE_HAL,
								g_hWnd, 
								D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
								&d3dpp, 
								&g_pD3DDevice);
	}

	// If the graphics card doesn't support hardware acceleration
	if (hr!=S_OK)
	{
		hr =
		g_pD3D->CreateDevice(	D3DADAPTER_DEFAULT, 
								D3DDEVTYPE_REF,
								g_hWnd, 
								D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
								&d3dpp, 
								&g_pD3DDevice);
	}

	if (FAILED(D3DXCreateSprite(g_pD3DDevice, &g_pD3DSprite)))
	{
		
	}

	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

	g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); 
	//g_pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); 
	//g_pD3DDevice->SetRenderState(D3DRS_ALPHAREF, (DWORD)8); 
	//g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);



	g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); 
	g_pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); 


	return true;
}// End CreateDX()

bool ReleaseDX()
{
	g_pD3DDevice->Release();
	g_pD3DDevice = NULL;

	g_pD3D->Release();
	g_pD3D = NULL;
	return true;
}// End ReleaseDX()

char g_dbg[128] = {0};
static bool g_rightMouseDown = false;
static POINT g_oldPoint = {0,0};

void SetLight()
{
	//Set a light up?
	D3DLIGHT9 d3dLight;

	//Initialize the light structure.
	ZeroMemory(&d3dLight, sizeof(D3DLIGHT9));

	//Set up a white point light at (0, 0, -10).
	d3dLight.Type = D3DLIGHT_DIRECTIONAL; //D3DLIGHT_POINT;

	// Actual colour of the light. (e.g. white).
	d3dLight.Diffuse.r = 1.0f;
	d3dLight.Diffuse.g = 1.0f;
	d3dLight.Diffuse.b = 1.0f;

	// Colour when no light hits the object.
	d3dLight.Ambient.r = 0.5f;
	d3dLight.Ambient.g = 0.5f;
	d3dLight.Ambient.b = 0.5f;

	// Shiny effect.
	d3dLight.Specular.r = 0.0f;
	d3dLight.Specular.g = 0.0f;
	d3dLight.Specular.b = 0.0f;

	d3dLight.Direction.x = 0.0f;
	d3dLight.Direction.y = -0.4f;
	d3dLight.Direction.z = 0.5f;

	d3dLight.Position.x = 50.0f;
	d3dLight.Position.y = 100.0f;
	d3dLight.Position.z = -20.0f;

	d3dLight.Attenuation0 = 0.1f; 
	d3dLight.Attenuation1 = 0.0f; 
	d3dLight.Attenuation2 = 0.0f; 
	d3dLight.Range = 5000.0f;

	g_pD3DDevice->SetLight(0, &d3dLight);
	g_pD3DDevice->LightEnable(0,true);

	//Turn on lighting
	//g_pD3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(100,100,100));
}

void KeyPresses()
{
	DirectInput* pInput = DirectInput::GetInstance();
	if (pInput->KeyPressed(DIK_1)) { g_wire			= !g_wire; }
	if (pInput->KeyPressed(DIK_2)) { g_paused		= !g_paused; }
	if (pInput->KeyPressed(DIK_3)) { g_staticPose	= !g_staticPose; }
	if (pInput->KeyPressed(DIK_4)) { g_drawNormals	= !g_drawNormals; }
	if (pInput->KeyPressed(DIK_5)) { g_drawBones	= !g_drawBones; }
	if (pInput->KeyPressed(DIK_6)) { g_transparent	= !g_transparent; }

}// End of KeyPresses(..)


void GameLoopDX()
{
	if(!g_pD3DDevice)return;


	// We use a more accurate timing information, QueryPerformanceCounter
	// instead of GetTickCount() so we get smoother animations
	LARGE_INTEGER freq;
	QueryPerformanceFrequency(&freq);

	LARGE_INTEGER nTime;
	QueryPerformanceCounter(&nTime);

	static LARGE_INTEGER oTime = nTime;

	double delay = (double(nTime.QuadPart - oTime.QuadPart)/freq.QuadPart);
	oTime=nTime;

	g_timeStep = (float)delay;

	if (g_timeStep > 1.0f)
	{
		g_timeStep = 1.0f;
	}

	static float updateFPS = 0.0f;
	updateFPS += (float)delay;
	static float fps = 1.0f/(float)delay;
	if (updateFPS>1.0f)
	{
		updateFPS=0.0f;
		fps = 1.0f/(float)delay;
	}

	extern HWND g_hWnd;
	static char title[256] = {0};

	sprintf(title, "X Txt Loader Demo - Parser/Drawer-FPS:%.1f,  TimeStep:%.2f", fps, g_timeStep);
	SetWindowText(g_hWnd, title);

	SetLight();

	KeyPresses();

	if (g_wire)	g_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
	else		g_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );

	Game::GetInstance()->UpdateGame();

	g_pD3DDevice->BeginScene();

	g_pD3DDevice->Clear(0, 
						NULL, 
						D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 
						D3DCOLOR_XRGB(88,88,88), 1.0f, 0 );

//	DebugDrawCross3D(g_pD3DDevice, camPosAt, 0.2f, 0xff00ff00);	
	Game::GetInstance()->RenderGame();

	g_pD3DDevice->EndScene();
	g_pD3DDevice->Present( NULL, NULL, NULL, NULL );
}// End GameLoopDX()

//------------------------------------------------------------------------------



long _stdcall MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	char Filename[MAX_PATH] = {0};

	switch (uMsg)
	{
		case WM_KEYDOWN:
		{
			switch( wParam )
			{
				case VK_ESCAPE:         // Exit on pressing Escape Key
					PostQuitMessage(0);
					break;
			}
		}
		break;

		case WM_MOUSEWHEEL:
		{
			float val = float(GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA);

			const float zoomSpeed = 0.001f;
			g_zoom += val * zoomSpeed;
		}
		break;
		case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;
	}

	return (long)DefWindowProc(hWnd, uMsg, wParam, lParam);
}// End MsgProc(..)


//------------------------------------------------------------------------------

// msvcrt.lib

int _stdcall WinMain(HINSTANCE i, HINSTANCE j, char* k, int) 
{
	// Turn on memory leak checking
	_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);

	MSG msg;
	char szname[] = "DX X File Format TXT Loader - Parser/Drawer";
	WNDCLASSEX wc = {	sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, 
		GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
		szname, NULL };
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	RegisterClassEx( &wc );

	ShowCursor(false);

	// Window menu 
	HMENU hmenu; 
	HMENU hmenupopup; 
	hmenu = CreateMenu(); 
	hmenupopup = CreateMenu(); 
	AppendMenu(hmenupopup, MF_STRING, ID_FILE_OPEN, "Open .x File"); 
	AppendMenu(hmenu, MF_POPUP,*((UINT*)&hmenupopup), "&File"); 


	g_hWnd = CreateWindowEx(	WS_EX_APPWINDOW,
		szname, szname, 
		WS_OVERLAPPEDWINDOW,
		50, 50, g_ScreenWidth,g_ScreenHeight,
		//60, 1000, 100,100,
		//50, 50, 840,700,
		GetDesktopWindow(), hmenu, wc.hInstance, NULL);


	DragAcceptFiles(g_hWnd, TRUE);

	CreateDX();
	IDirect3DDevice9* pd = g_pD3DDevice;

	ShowWindow(g_hWnd, SW_SHOW);
	UpdateWindow(g_hWnd);

	Game* pGame = Game::GetInstance();
	pGame->InitGame(g_hWnd, wc.hInstance);

	CCamera::GetInstance()->Initialize(pd,D3DXVECTOR3(0.0f, 50.0f, 0.0f), g_ScreenWidth, g_ScreenHeight, 1.0f, 5000.0f);

	while(1)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if (!GetMessage(&msg, NULL, 0, 0))
				break;
			DispatchMessage(&msg);
		}
		else
		{
			GameLoopDX();
		}
	}

	Game::GetInstance()->EndGame();
	ReleaseDX();

	//VLD NOW
	//_CrtDumpMemoryLeaks();

}// End WinMain(..)


//------------------------------------------------------------------------------